<?php

/*
 * -File        $Id: init.php,v 1.15 2005/06/01 20:01:58 albertlash4 Exp $
 * -License     LGPL (http://www.gnu.org/copyleft/lesser.html)
 * -Copyright   2004, Nexista
 * -Author      joshua savage, js@nexista.com
 */

/**
 * @package Nexista
 * @author Joshua Savage <js@nexista.com>
 */
 

/**
 * Load required runtime files
 */
require_once(NX_PATH_CORE. "config.php");
require_once(NX_PATH_CORE. "error.php");
require_once(NX_PATH_CORE. "path.php");
require_once(NX_PATH_CORE. "flow.php");
require_once(NX_PATH_CORE. "debug.php");
require_once(NX_PATH_CORE. "auth.php");

/**
 * This class is reponsible for initializing the runtime process.
 *
 * It is responsible for loading certain required files,
 * initializing sessions, flow, etc.... and processing the 
 * correct files based on request and finally outputting the data.
 *
 * The default output functionality, Init::display(), can be overriden 
 * with a custom function as defined by Init::registerOutputHandler. This function 
 * will then call the output command Init::run() itself and perform any desired
 * pre-display processing such as cache the output, etc...
 *
 * Here is an example (in the prepend file) of setting up caching 
 * with PEAR::Cache_Lite:
 * <code>
 * //register a custom output handler
 * Init::registerOutputHandler('initOutput');
 * 
 * function initOutput($init)
 * {
 *      //process sitemap and locate file
 *      $init->process();
 *
 *      $group = null;
 *      $noTest = true;
 *      $options = array(
 *          'cacheDir' =&gt; NX_PATH_CACHE,
 *          'caching' =&gt; Config::get('runtime/cache'),
 *          'lifeTime' => $init->info['cacheExpiryTime']);
 *
 *      if($options['caching'] AND !empty($options['lifeTime']))
 *      {
 *          //note: a cache time of 0 may or may not mean 'forever' in your cache
 *          //system. For PEAR::Lite it does not, so we change it to a huge value
 *          if($options['lifeTime'] === 0)
 *              $options['lifeTime'] = 999999999999;
 *          require_once(NX_PATH_LIB.'PEAR/Lite.php');
 *          $cache = new Cache_Lite($options);
 *
 *          //create a cache id. we use url here but whatever makes you happy
 *          $cache_id = $_SERVER['REQUEST_URI'];
 * 
 *          //see if there is a valid cached version
 *          if(isset($cache_id) AND ($result = $cache-&gt;get($cache_id, $group, $noTest)))
 *          {
 *              //there is. we display it
 *              echo $result;
 *          }
 *          else
 *          {
 *              //here we called the Init::run method to process gate and get output
 *              $result = $init-&gt;run();
 *              //we cache it
 *              $cache-&gt;save($result, $cache_id, $group);
 *              //and diplay
 *              echo $result;
 *          }
 *      }
 *      else
 *      {   
 *          ob_start();
 *          echo $init->run();
 *          ob_end_flush();
 *      } 
 * }</code>
 *
 * @package     Nexista
 */


// REALLY DIRTY UGLY HACK!!!
require_once(NX_PATH_CORE.'ImportStream.php');
ImportStream::registerImportHandler('getXsl');
stream_wrapper_register('svn', 'ImportStream');
function getXsl($path)
{        
	 $xslfile = NX_PATH_XSL.$path;
	if(!file_exists($xslfile)) 
	{
        
		Error::init('Error processing XSL file (the file is missing!): '.$xslfile, NX_ERROR_FATAL);
		exit;
	}
	 return($xslfile);
}


Error::addObserver('display', 'observerDisplay');
function observerDisplay($e)
{
   $e->toHtml();  
}


function authLogin($auth)
{
    if(empty($_SESSION['authReferer']))
    {
        $_SESSION['authReferer'] = $_SERVER['REQUEST_URI'];
    }
    header("Location: ".NX_LINK_PREFIX."login/");
    exit;
}

Auth::registerTimeoutHandler('authLogin');
Auth::registerLoginHandler('authLogin');
Auth::registerDeniedHandler('authLogin');
Auth::registerExpiredHandler('authLogin');

// END HACK
		


class Init
{

    
    /**
     * Hold an instance of the class
     *
     * @var     object   
     */
     
    static private $instance;
    
    
    /**
     * Output handler
     *
     * @var     mixed   
     */
     
    static private $outputHandler;
    
    
    /**
     * Config object
     *
     * @var     object   
     */

    private $config;

    
    /**
     * Execution timer flag
     *
     * @var     boolean
     */

    public $timer = false;
    
    
    /**
     * Information array about currently processed gate
     *
     * @var     array
     */

    private $info = array();
    

    /**
     * Constructor - inits config
     *
     */
 
    public function __construct()
    { 
        
		
		$this->startTimer();
        $this->loadConfig(); 
        $this->initError();  
    }
    
    
    /**
     * Startup functions, init...
     *
     * This method is responsible for calling all
     * startup functions such as timers, flow init, etc..
     *
     */
     
    public function start()
    {            
        $this->setDebug();
        $this->initSession();
        $this->initFlow();       
    }
    

    /**
     * Loads site configuration info
     *
     */

    public function loadConfig()
    {
        $this->config = Config::singleton();
        $this->config->setMaster(NX_PATH_COMPILE.'config.xml'); 
        $this->config->loadMasterConfig();
    }
    
    
    /**
     * Loads prepend file
     *
     * The prepend file is an optional file as defined in config.
     * While it can be used to hold any php code that the user may wish to
     * have processed everytime but is specifically designed to run code
     * before any output. Examples are headers and sessions.
     *
     * @param   mixed       valid php callback
     */

    public function loadPrepend($prepend)
    {
        require_once($prepend);
    }
    

    /**
     * Shutdown and cleanup
     *
     * This method is responsible for shutting down the
     * current request. It will clean up variables,
     * send ob to ouput, etc..
     *
     */

    public function stop()
    {
        $this->stopTimer();
        exit();

    }

    
    /**
     * Set up the error/exception handler
     *
     */

    private function initError()
    { 
        //$error = Error::singleton();
        //set_exception_handler(array($error,'exceptionHandler'));
    }
    
    
    /**
     * Init Flow
     *
     * This method creates an instance of Flow
     * which is the class responsible for all
     * data communication between sitemap modules (tags)
     *
     */

    private function initFlow()
    { 
        $flow = Flow::singleton();        
        $flow->init();       
    }

    
    /**
     * Init sessions
     *
     * This method starts up a session
     * and globalizes it.
     *
     */

    function initSession()
    {    
		

		$params = $this->config->getSection('session');
		// Also check for cache_limiter - if its public, no session!
		if($params['active']==0) { 
			return false;
		} else { 
		   
			if(!empty($params['cookieLifetime']))
				session_set_cookie_params($params['cookieLifetime']);
			if(!empty($params['cacheLimiter']))
				session_cache_limiter($params['cacheLimiter']);
			if(!empty($params['cacheExpires']))
				session_cache_expire($params['cacheExpires']);

			@session_start();
			define('NX_SESSION_ID', session_name().'='.session_id());
			
			return true;
		}
    }


    /**
     * Starts timer
     */

    private function startTimer()
    {
        $GLOBALS['debugStartTime'] = microtime();
    }


    /**
     * Stop timer
     *
     */

    private function stopTimer()
    {
        if($this->timer)
        {
            print("<br><b>Execution time: </b>". Debug::profile()." seconds");
        }
    }

    
    /**
     * Reads sitemap for current gate data
     *   
     * This function retrieves the correct gate based on request.
     */

    public function process()
    {        


        require_once(NX_PATH_COMPILE.'sitemap.php');
        $this->info['uri'] = false;
        if(isset($gatesExact[$_ID_]))
        {
            $this->info['uri'] = $gatesExact[$_ID_]['uri'];
            if(isset($gatesExact[$_ID_]['cache']))
                $this->info['cacheExpiryTime'] = $gatesExact[$_ID_]['cache'];
				
			if(isset($gatesExact[$_ID_]['role'])) {
                $this->info['requireRole'] = $gatesExact[$_ID_]['role'];
				// I wonder why this wasn't here in the first place?
				$auth = Auth::singleton();
				$auth->requireRole($this->info['requireRole']);
			}
        } 
        elseif(isset($gatesRegex)) 
        {
			
            foreach($gatesRegex as $regex=>$info) 
            {
				
				//$pattern = "/^(.".$pattern.")$/";
                if(preg_match("/".$regex."/",$_ID_,$match ))
                {
                    //globalize the match in case we need it
                    $GLOBALS['regex'] = $match;
                    $this->info['uri'] = $info['uri'];
                    if(isset($info['cache']))
                        $this->info['cacheExpiryTime'] = $info['cache'];
					if(isset($info['role'])) {
                        $this->info['requiredRole'] = $info['role'];
						$auth = Auth::singleton();
						$auth->requireRole($info['role']);
					}
                    break;
                }
            }
        }     
    }
           
    /**
     * Pocesses final output
     *   
     * This function processes the correct  gate based 
     * on request. In the event of not finding the 
     * correct gate, it will attempt to load the gate defined
     * under runtime/missing in config. Failure to do so
     * will result in a 404 redirect to be handled by the web server.
     */
     
    public function run()
    {

        if(!empty($this->info['uri'])) 
        {
            require(NX_PATH_COMPILE.$this->info['uri']);
            if(isset($debugOutput)) { 
				return $debugOutput.$output;
			} else { 
				return $output;
			}
        } 
        elseif(!is_null($gateMissing))
        {
            require(NX_PATH_COMPILE.$gateMissing);
            return $debugOutput.$output;
        }
        else
        {
        //echo $_GET['nid'];
	//	echo "<br/>";
	//	echo $_SERVER['REQUEST_URI'];
	//	echo $_GET['page'];
	//	exit;
            //ob_end_clean();
           		 header('HTTP/1.x 404 Not Found');
			//$server_name = $_SERVER['SERVER_NAME'];
			//$error_file = "/var/www/dev/".$server_name."/htdocs/resources/errors/404.html.gz";
			//if(is_file($error_file)) { 
			//	header("Content-encoding: gzip");
			//	readfile($error_file);
			//} else { 
				echo "Page not found: $error_file";
			//}
			//get error page from config.
            exit;
        }        
    }
    
    /**
     * Displays final output
     *   
     * This method is called from the loader file and is
     * responsible for activating the run process and displaying
     * the output. 
     * In the event that caching or an other pre-display processing
     * is needed, this method can be overriden using a callback function
     * registered with Init::registerOutputHandler();
     * This function needs to be a valid php callback (see call_user_func())
     * It needs to accept one argument, the reference to the Init object.
     * It also needs to call the static Init::run() method and capture/display
     * the returned string.
     *
     * Here is an example
     */

     public function display()
     { 
		
		
		 
        //output handler defined?
        if(!is_null(self::$outputHandler)) 
        {            
            echo call_user_func(self::$outputHandler, $this);
        }
        //no output handler defined - just spit it out
        else
        {
            //process sitemap and locate file
            $this->process();
            ob_start();
            echo $this->run();
            ob_end_flush();
        }
     }    
	 
	/**
	 * Returns the gate info in an array consisting only of the params
	 * that are specified by the sitemap. Possible items include: 
	 * uri (always present), cache, and role. 
	 *
	 */
	public function getInfo($data)
	{
		if(isset($this->info[$data])) { 
			return $this->info[$data];
		} else { 
			return false;
		}
	}

     
    /**
     * Defines debug / error levels and reporting - this needs some help. 
     *
     */

    private function setDebug()
    {
        //get the config vars    
        $configs = $this->config->getSection('runtime');

        if(isset($configs['track']) && ($configs['track'] == 'on'))
        {
            $GLOBALS['debugTrack'] = true;

        }
        if(isset($configs['timer']) && ($configs['timer'] == 'on'))
        {
            //start timer
            $this->timer = true;

        }

        if(isset($configs['debug']) && ($configs['debug'] == 'true'))
        {
            define('NX_DEBUG', true);
        }
        else
        {
            define('NX_DEBUG', false);
        }


       // $error =& new Error($configs);
        return true;
    }

    
    /**
     * Registers a function to be called on output
     * 
     * This function can be used to manipulate the final output before it is
     * displayed. It can be used to create a caching system, compress output etc...
     *
     * The handler should be a callable function or array of object/method as
     * defined in is_callable php function.  It should accept 1 arguments:
     * 1. The reference to the init class instance
     *
     * Note that the Init::$info property contains the current cache value
     * from the sitemap if set.
     *
     * This function should call:
     *      $output = Init::run();
     * to get the final output. The function is responsible for displaying it.
     *
     * @param  mixed        a function or an array of class=>method
     */
     
    static public function registerOutputHandler($handler)
    {             
        if(is_callable($handler))   
            self::$outputHandler = $handler;
        else
            NexistaException::init("Init Output Handler is not callable!");
    }

    
       
    /**
     * Returns a class singleton.
     *
     * @return  object      class singleton instance
     */
     
    static public function singleton() 
    {
        if (!isset(self::$instance)) {
            $c = __CLASS__;
            self::$instance = new $c;
        }

        return self::$instance;
    }

    

} //end class

?>
